local parseQuery = require("querystring").parse
local cookie = require("luv-http.cookie")
local session = require("luv-http.session")

local modifyReqResp = function (req, resp, ctx)
    local requesturi, querystring = req.url:match("^([^?]*)%??(.*)")
    req.requesturi = requesturi --添加请求路径
    req.querystring = querystring --添加查询字符串
    if #querystring > 0 then
        req.query = parseQuery(querystring) --添加查询参数
    end
    req.cookies = cookie.getCookie(req) --解析cookie

    cookie.bindSetCookie(resp) --绑定设置cookie的方法

    session.bindGetSession(req, resp, ctx, {
        timeout = ctx.envCfg.sessionTimeout
    }) --绑定getSession方法
    local session = req:getSession()
    session._updateSession() --更新session的过期时间
end

local dispatchHandler = function (handlers, req, resp, ctx)
    for index, handler in ipairs(handlers) do
        if handler.match(req, resp, ctx) then
            handler.handle(req, resp, ctx)
            break
        end
    end
end

local dispatchFilter = function (filters, req, resp, ctx)
    local index = 0
    local go --下一个处理器处理
    go = function ()
        index = index + 1
        local filter = filters[index]
        if filter then
            if filter.match(req, resp, ctx) then
                filter.handle(req, resp, ctx, go)
            else
                go()
            end
        end
    end
    go()
    resp:_end()
end

local getDispatcher = function (appFilters, wsRouteHandlers, appHandlers, staticHandler)
    if not appFilters then
        appFilters = {}
    end
    if not wsRouteHandlers then
        wsRouteHandlers = {}
    end
    if not appHandlers then
        appHandlers = {}
    end
    local allHandler = {}
    --添加app里面的websocket路由生成的处理器
    for _, handler in ipairs(wsRouteHandlers) do
        table.insert(allHandler, handler)
    end
    --添加app里面的routes生成的处理器
    for _, handler in ipairs(appHandlers) do
        table.insert(allHandler, handler)
    end
    if staticHandler then
        --静态文件处理器添加到最后
        table.insert(allHandler, staticHandler)
    end

    --把所有的处理器包装到一个过滤器里面
    local handleFilter = {}
    handleFilter.match = function (req, resp, ctx)
        return true
    end
    handleFilter.handle = function (req, resp, ctx, go)
        dispatchHandler(allHandler, req, resp, ctx)
    end

    local allFilter = {}
    --添加业务过滤器
    for _, filter in ipairs(appFilters) do
        table.insert(allFilter, filter)
    end
    --添加所有处理器包装成的过滤器(最后一个处理过滤器)
    table.insert(allFilter, handleFilter)

    local dispatcher = function (req, resp, ctx)
        coroutine.wrap(function ()
            local ret = xpcall(function()
                modifyReqResp(req, resp, ctx)
                dispatchFilter(allFilter, req, resp, ctx)
            end, function()
                print(debug.traceback())
            end)
            if not ret then
                resp.statusCode = 500
                resp:_end()
            end
        end)()
    end
    return dispatcher
end

local moduleName = ...
_G[moduleName] = getDispatcher
complex = getDispatcher
return complex